//===- rmLoads.cpp - Example code from "Writing an LLVM Pass" -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements two versions of the LLVM "Hello World" pass described
// in docs/WritingAnLLVMPass.html
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/Statistic.h"
#include "llvm/IR/Function.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instruction.h"
#include <string>

using namespace llvm;

#define DEBUG_TYPE "rmLoads"
#define FIRST_OPERAND 0
#define SECOND_OPERAND 1
STATISTIC(Counter, "Counts number of functions greeted");

namespace{

/*******************************************************************************
  rmLoads 
  
  This class performs a pass inheriting Function Pass Class and overriding 
  runOnFunction method in order to remove useless loads in same basic blocks. 
 
  Class Variables
  -----------------
  char  ID                         Pass identification, replacement for typeid
  int   instCounter                Keeps the number of instruction 
  bool  isChanged;                 Keeps the information whether a program is
                                   modified or not  
  
  Instance Varibles
  -----------------
  map  <int, Instruction*>                        InstructionMap 
  Matches a unique key to an instruction
  
  map    <int, Instruction*>::iterator            iterForPrint
  Points a pair in the InstructionMap
  
  pair   <int, Instruction*>                      currentPair
  It is an element of InstructionMap
 
  vector <int>                                    uselessInstNumber
  It keeps useless instruction numbers which are unique keys in the 
  InstructionMap
    
  string                                          store 
  It keeps operand names in store instructions 
  
  string                                          load
  It keeps operand names in load instructions 
  
  Value                                           *valueStoreReplaceWith
  It is a pointer to operand that is first one in store instruction
       
  Value                                           *valueStore
  It is a pointer to operand that is second one in store instruction
       
  Value                                           *valueLoad
  It is a pointer to operand that is first one in load instruction
  
  Instruction                                     *ii
  It is a pointer to store instruction
                     
  bool                                            storeFlag
  It is flag to prevent processing store-load consecutive instructions in 
  different basic blocks 
  
*******************************************************************************/
  struct rmLoads : public FunctionPass 
  {
   
    static char  ID; // Pass identification, replacement for typeid
    static int   instCounter;
    static bool  isChanged;     
    rmLoads() : FunctionPass(ID) {}
    
    bool runOnFunction(Function &F) override {
     
      std::map    <int, Instruction*> InstructionMap;
      std::map    <int, Instruction*>::iterator iterForPrint;
      std::pair   <int, Instruction*> currentPair;
      std::vector <int> uselessInstNumber; 
      std::string             store, 
                               load; 
      Value  *valueStoreReplaceWith,        
                        *valueStore, 
                         *valueLoad;
      Instruction              * ii;                   
      bool                storeFlag;       
      ++Counter;
      for (Function::iterator b = F.begin(), be = F.end(); b != be; ++b){	  
          storeFlag = false;// to make sure consecutive store and load 
                            //instructions are in the same basic block
         for (BasicBlock::iterator i = b->begin(), ie = b->end(); i != ie; ++i){
               currentPair = std::make_pair(instCounter, i);
               InstructionMap.insert(currentPair);
	          if(i->getOpcode() == Instruction::Store){	
	               storeFlag = true; // Store instruction is found!!!                    
                    ii        = i;    // keep the pointer to instruction for the 
                                      // next immediate load instruction
	          }    	
	          // To check whether or not the current insruction is Load 
	          // and the previous one is store in the same basic block. 
	          if(i->getOpcode() == Instruction::Load && storeFlag == true ){	
		         storeFlag  = false;		          		         		  
                   valueStore = dyn_cast<Value>(ii->getOperand(SECOND_OPERAND));
                   valueLoad  = dyn_cast<Value>(i->getOperand(FIRST_OPERAND));              
	              // Get first operand from the store instruction to replace
	              valueStoreReplaceWith =
	                            dyn_cast<Value>(ii->getOperand(FIRST_OPERAND));
                    if(valueLoad->hasName() && valueStore->hasName()){
	                    load  = valueLoad->getName(); 
	                    store = valueStore->getName();
	                    if(load.compare(store) == 0){
	                         //errs()<< store<<" matched "<<load<<"\n";
		                    //errs()<<"Instruction Store :"<<*ii<<'\n';
	                         //errs()<<"Instruction Load :"<<*i<<"\n\n\n";
	                         //errs()<<"Instruction "<< instCounter<<" is useless load"<<"\n";
	                         uselessInstNumber.push_back(instCounter);
	                         i->replaceAllUsesWith(valueStoreReplaceWith);
	                         isChanged = true;
		               } 
		          }	         
	          }
               instCounter++;
	     }
      }
      // Print out useless load instructions      
      for(std::vector<int>::iterator iter  = uselessInstNumber.begin(); 
	                                iter != uselessInstNumber.end(); ++iter){
	                                
          iterForPrint = InstructionMap.find(*iter);
    	     errs()<<"Instruction "<<iterForPrint->first
    	           <<" is a useless load "<<'\n';
          iterForPrint->second->eraseFromParent();
      }
	 InstructionMap.clear();
      uselessInstNumber.clear();
      return isChanged;
    }// runOnFunction
  }; // rmLoad
}// namespace

bool rmLoads::isChanged   = false; 
int  rmLoads::instCounter = 1; 
char rmLoads::ID          = 0;
static RegisterPass<rmLoads> X("rmLoads","removing unnecessary loads",false,false);

namespace {
  // Hello2 - The second implementation with getAnalysisUsage implemented.
  struct Hello2 : public FunctionPass {
    static char ID; // Pass identification, replacement for typeid
    Hello2() : FunctionPass(ID) {}

    bool runOnFunction(Function &F) override {
     // ++HelloCounter;
      errs() << "Hello: ";
      errs().write_escaped(F.getName()) << '\n';
      return false;
    }

    // We don't modify the program, so we preserve all analyses.
    void getAnalysisUsage(AnalysisUsage &AU) const override {
      AU.setPreservesAll();
    }
  };
}

char Hello2::ID = 0;
static RegisterPass<Hello2>
Y("hello2", "Hello World Pass (with getAnalysisUsage implemented)");
